package com.thinkcms.security.custom;

import com.thinkcms.core.api.BaseRedisService;
import com.thinkcms.core.config.ThinkCmsConfig;
import com.thinkcms.core.constants.Constants;
import com.thinkcms.core.constants.MinAppConstant;
import com.thinkcms.core.handler.CustomException;
import com.thinkcms.core.utils.ApiResult;
import com.thinkcms.core.utils.BaseContextKit;
import com.thinkcms.core.utils.Checker;
import com.thinkcms.core.utils.SecurityConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import java.util.Collection;
import java.util.HashSet;
import java.util.Map;

public abstract class AbsCustomJwtHandler {

    @Autowired
    BaseRedisService<String,Object> baseRedisService;

    @Autowired
    ThinkCmsConfig thinkCmsConfig;

    //处理jwt 并判断是否合法
    public abstract void handlerJwtToken(Authentication authentication, JwtTokenStore tokenStore) throws CustomException;

    protected void handAppUserSession(Map<String, Object> details,String tokenValue){
        handAppToken(tokenValue);
        String openId = Checker.BeNull(details.get(MinAppConstant.OPENID)) ? null : details.get(MinAppConstant.OPENID).toString();
        String userId = Checker.BeNull(details.get(MinAppConstant.USERID)) ? null : details.get(MinAppConstant.USERID).toString();
        ckparameters(openId,userId);
        BaseContextKit.setOpenId(openId);
        BaseContextKit.setUserId(userId);
    }


    protected void handPlatUserSession(Map<String, Object> details,String tokenValue){
        String uid = Checker.BeNull(details.get(SecurityConstants.USER_ID)) ? null : details.get(SecurityConstants.USER_ID).toString();
        String deptId = Checker.BeNull(details.get(SecurityConstants.DEPT_ID)) ? null : details.get(SecurityConstants.DEPT_ID).toString();
        String userName = Checker.BeNull(details.get(SecurityConstants.USER_NAME)) ? null : details.get(SecurityConstants.USER_NAME).toString();
        String name = Checker.BeNull(details.get(SecurityConstants.NAME)) ? null : details.get(SecurityConstants.NAME).toString();
        Collection<String> roleSigns = Checker.BeNull(details.get(SecurityConstants.ROLE_SIGNS)) ? new HashSet<>() : (Collection<String>) details.get(SecurityConstants.ROLE_SIGNS);
        ckparameters(uid);
        if(!thinkCmsConfig.getAllowMultiLogin()){
            checkAllowMulitLogin(uid,tokenValue);
        }
        BaseContextKit.setUserId(uid);
        BaseContextKit.setUserName(userName); //设置账号
        BaseContextKit.setDeptId(deptId);
        BaseContextKit.setName(name);
        BaseContextKit.setRoleSigns(roleSigns);
    }

    private void ckparameters(String... params){
        if(params.length>0){
            for(int i=0; i < params.length;i++){
                if (Checker.BeBlank(params[i])) {
                    throw new InvalidTokenException("Invalid jwt token!");
                }
            }
        }
    }

    private void checkAllowMulitLogin(String userId,String tokenValue){
        if(Checker.BeNotBlank(userId)&&Checker.BeNotBlank(tokenValue)){
            Object redisTokenValue = baseRedisService.get(Constants.AllowMultiLoginKey+userId);
            if(Checker.BeNotNull(redisTokenValue)){
                boolean singleLogin=tokenValue.equals(redisTokenValue.toString());
                if(!singleLogin){
                    throw new AccessDeniedException("您的账号已经在别处登录,您被迫下线! ");
                }
            }
        }
    }

    private void handAppToken(String tokenValue){
        Boolean hasKey= baseRedisService.hasKey(tokenValue);
        if(!hasKey){
            throw new CustomException(ApiResult.result(7000));
        }
        baseRedisService.setSetExpireTime(tokenValue,SecurityConstants.expireTime);
    }
}
